/**
 * MIT License
 * <p>
 * Copyright (c) 2017-2018 nuls.io
 * <p>
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * <p>
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * <p>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package io.nuls.klines.service;

import io.nuls.klines.dao.SyncInfoDao;
import io.nuls.klines.entity.KlineModel;
import io.nuls.klines.dao.ExchangeInfoDao;
import io.nuls.klines.dao.KlinesDao;
import io.nuls.klines.entity.ExchangeInfoEntity;
import io.nuls.klines.entity.KlinesEntity;
import io.nuls.klines.entity.SyncInfoEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author: PierreLuo
 * @date: 2021-03-04
 */
@Service
public class AppService {

    @Resource
    ExchangeInfoDao exchangeInfoDao;
    @Resource
    KlinesDao klinesDao;
    @Resource
    SyncInfoDao syncInfoDao;


    public SyncInfoEntity getTodaySyncInfo(String txDay) {
        return syncInfoDao.findFirstByTxDay(txDay);
    }

    public SyncInfoEntity saveSyncInfo(SyncInfoEntity e) {
        return syncInfoDao.saveAndFlush(e);
    }

    public void updateSyncInfo(SyncInfoEntity e) {
        syncInfoDao.saveAndFlush(e);
    }

    public long existUnSyncExchange(String txDay) {
        return  exchangeInfoDao.countByDayIsNot(txDay);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
    public void saveExchangeInfo(List<Map> symbols) {
        /**
         * 只存储新增的xxx/USDT的交易对
         */
        for (Map symbolMap : symbols) {
            String symbol = symbolMap.get("symbol").toString().toUpperCase();
            if (symbol.endsWith("USDT")) {
                List<ExchangeInfoEntity> list = exchangeInfoDao.findBySymbol(symbol);
                if (list == null || list.isEmpty()) {
                    ExchangeInfoEntity entity = new ExchangeInfoEntity();
                    entity.setSymbol(symbol);
                    entity.setDay("0");
                    exchangeInfoDao.saveAndFlush(entity);
                }
            }
        }
    }

    public List<ExchangeInfoEntity> getAllExchangeList() {
        return exchangeInfoDao.findAll();
    }


    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
    public void saveKlines(ExchangeInfoEntity exchange, LinkedList<KlineModel> modelList) {
        //先更新交易对的同步日期
        exchangeInfoDao.saveAndFlush(exchange);

        /*
         * 筛选条件：
         * 昨天k线开盘价 < 收盘价，且开盘价 ≤ ma5均线 ≤ 收盘价，且开盘价 ≤ ma10均线 ≤ 收盘价，且开盘价 ≤ ma20均线 ≤ 收盘价
         */

        //取出第一条数据，第一条数据就是昨天的K线
        KlineModel model = modelList.removeFirst();
        //判断开盘价 < 收盘价
        if (model.getOpenPrice().compareTo(model.getEndPrice()) > 0) {
            return;
        }

        //计算ma5金额， ma5 = 前5天收盘价之和 / 5
        BigDecimal ma5 = getMaValue(modelList, 5);
        //开盘价 ≤ ma5均线 ≤ 收盘价
        if (model.getOpenPrice().compareTo(ma5) > 0 || ma5.compareTo(model.getEndPrice()) > 0) {
            return;
        }

        //计算ma10金额
        BigDecimal ma10 = getMaValue(modelList, 10);
        if (model.getOpenPrice().compareTo(ma10) > 0 || ma10.compareTo(model.getEndPrice()) > 0) {
            return;
        }

        //计算ma20金额
        BigDecimal ma20 = getMaValue(modelList, 20);
        if (model.getOpenPrice().compareTo(ma20) > 0 || ma20.compareTo(model.getEndPrice()) > 0) {
            return;
        }

        KlinesEntity entity = new KlinesEntity(exchange, model, ma5, ma10, ma20);
        klinesDao.saveAndFlush(entity);
    }


    private BigDecimal getMaValue(LinkedList<KlineModel> modelList, int value) {
        BigDecimal ma = BigDecimal.ZERO;
        for (int i = 0; i < value; i++) {
            KlineModel model = modelList.get(i);
            ma = ma.add(model.getEndPrice());
        }
        ma = ma.divide(new BigDecimal(value)).setScale(4, RoundingMode.HALF_UP);
        return ma;
    }


    public List<KlinesEntity> getKlineList(String txDay) {
        return klinesDao.findByTxDay(txDay);
    }
}
